// ==================================================================================
// Shared Genomics Project MPI Codebase
// Version 1.0 30/04/2010
//
// (c) 2010 University of Manchester all rights reserved
//
// This file is distributed under the GNU General Public License, Version 2.  
// Please see the file COPYING.txt for more details
// ==================================================================================

/*!
\file
\brief	Implementation of Utility Functions for Version 2 Epistasis programs 
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#include "adjusted_2d.h"
#include "copyfile.h"
#include "epi_utils.h"
#include "pmaths.h"
#include "suffixes.h"
#include "utils.h"

void epi_utils_cleanup(struct selected_options *ops, int mode, int numprocs, int snpMajor) {
	int i;
	char remoteFilepath[FILE_PATH_LENGTH];

	if (ops != NULL && strlen(ops->szRunId) > 0 && strlen(ops->rdir) > 0) {
		if (mode == MODE_NON_PERMUTED_MERGE) {
			for (i = 0; i < numprocs; i++) {
				sprintf(remoteFilepath, "%s%s_%i%s", ops->rdir, ops->szRunId, i, SUFFIX_RAW_EPI_FILE);
				deleteFile(remoteFilepath);
			}
		} else if (mode == MODE_STOP || mode == MODE_PERMUTED_MERGE) {
			for (i = 0; i < numprocs; i++) {
				sprintf(remoteFilepath, "%s%s_%i%s", ops->rdir, ops->szRunId, i, SUFFIX_REPI_FILE);
				deleteFile(remoteFilepath);
			}
			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_EPI_FILE2);
			deleteFile(remoteFilepath);

			if (snpMajor) sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_SPED_FILE);
			else sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_IPED_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_BMAP_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_PERM_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_RSEED_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_SAMPLE_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_PADJ_FILE);
			deleteFile(remoteFilepath);

			sprintf(remoteFilepath, "%s%s%s", ops->rdir, ops->szRunId, SUFFIX_PERSON_TO_DEL);
			deleteFile(remoteFilepath);
		}
	} 
}

int epi_util_perm_counts_write_and_copy(struct selected_options *ops, int numprocs, int start_perm, int end_perm, struct adjusted_2d *adj, int nAdj, int *R, int *maxR, int *nInts, int rank) {
	FILE *out = NULL;
	BOOL jobDone = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];

	if (ops == NULL || numprocs <= 0 || adj == NULL || nAdj <= 0 || R == NULL || maxR == NULL || nInts == NULL || rank < 0) return 0;
	else if (strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(ops->szRunId) == 0) return 0;

	set_datafile_path(localFilepath, ops->ldir, ops->szRunId, rank, SUFFIX_REPI_FILE);
	set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, rank, SUFFIX_REPI_FILE);
	out = fopen(localFilepath, "w");
	if (out != NULL) {
		int i;

		// Header lines, numprocs and the number of permutations this rank is running.
		fprintf(out, "%i\n", numprocs);
		fprintf(out, "%i\n", abs(end_perm - start_perm));
		for (i = 0; i < nAdj; i++) fprintf(out, "%i,%i,%i,%i,%i\n", adj[i].p1, adj[i].p2, R[i], maxR[i], nInts[i]);
		fclose(out);
		if (copyAndDeleteFile(localFilepath, remoteFilepath)) jobDone = TRUE;
	}

	if (jobDone) return 1;
	else return 0;
}

int epi_util_perm_counts_read(struct selected_options *ops, struct adjusted_2d *adj, int nAdj, int *R, int *maxR, int *nInts, int *numprocs) {
	int _numprocs = 0, i, j;
	BOOL jobDone = FALSE, hasCopiedFile = FALSE;
	char localFilepath[FILE_PATH_LENGTH], remoteFilepath[FILE_PATH_LENGTH];
	char token[TOKEN_LENGTH], line[MAX_LINE_LENGTH];

	if (ops == NULL || adj == NULL || nAdj <= 0 || R == NULL || maxR == NULL || nInts == NULL || numprocs == NULL) return 0;
	else if (strlen(ops->ldir) == 0 || strlen(ops->rdir) == 0 || strlen(ops->szRunId) == 0) return 0;

	_numprocs = readNumberOfProcs(remoteFilepath, line, MAX_LINE_LENGTH, ops->rdir, ops->szRunId, SUFFIX_REPI_FILE);
	*numprocs = _numprocs;
	if (_numprocs == 0) return 0;

	// Copy data files to the local working directory.
	for (i = 0; i < _numprocs; i++) {
		set_datafile_path(remoteFilepath, ops->rdir, ops->szRunId, i, SUFFIX_REPI_FILE);
		set_datafile_path(localFilepath, ops->ldir, ops->szRunId, i, SUFFIX_REPI_FILE);
		if (copyFile(remoteFilepath, localFilepath)) hasCopiedFile = TRUE;
	}
	if (!hasCopiedFile) return 0;
	qsort(adj, nAdj, sizeof(struct adjusted_2d), adjusted_2d_cmp);
	
	for (i = 0; i < _numprocs; i++) {
		int nLinesRead = 0;
		FILE *in = NULL;
		set_datafile_path(localFilepath, ops->ldir, ops->szRunId, i, SUFFIX_REPI_FILE);
		in = fopen(localFilepath, "r");
		if (in != NULL) {
			struct adjusted_2d interaction;

			fgets(line, MAX_LINE_LENGTH, in); // Skip the numprocs header line.
			fgets(line, MAX_LINE_LENGTH, in); // The number of permutations

			// Loop through the rest of the file to get the permutation counts.
			while(fgets(line, MAX_LINE_LENGTH, in) != NULL) {
				int index = -1;
				j = 0;
				get_token(line, token, j++, ',');
				interaction.p1 = atoi(token);
				get_token(line, token, j++, ',');
				interaction.p2 = atoi(token);
				index = adjusted_2d_search(adj, nAdj, &interaction);
				if (index >= 0) {
					get_token(line, token, j++, ',');
					R[index] += atoi(token);
					get_token(line, token, j++, ',');
					maxR[index] += atoi(token);
					get_token(line, token, j, ',');
					nInts[index] += atoi(token);
					nLinesRead++;
				}
			}
			fclose(in);
			if (nLinesRead > 0) jobDone = TRUE;
		}
		deleteFile(localFilepath);
	}

	if (jobDone) return 1;
	else return 0;
}

int epi_util_set_2d_limits(int myrank, int nSNPs, int numprocs, int *limits) {
	int np = 0, iteractionsPerProcessor = 0;

	if (myrank < 0 || nSNPs <= 0 || numprocs <= 0 || limits == NULL) return 0;
	
	limits[0] = 0;
	limits[1] = 0;

	np = getPairwiseTests(nSNPs);
	iteractionsPerProcessor = getPairwiseTestsPerNode(nSNPs, numprocs);
	limits[0] = myrank * iteractionsPerProcessor;
	limits[1] = limits[0] + iteractionsPerProcessor - 1;
	if (limits[1] > np || myrank == numprocs - 1) limits[1] = np - 1;
	
	return 1;
}